package util;

import sort.QuickSort;
import sort.Sortable;

import java.util.Arrays;
import java.util.Random;

/**
 * 检验排序算法的对数器类
 *
 * @author Liaorun
 */
public class Comparator {


    /**
     * 测试几次
     */
    private int testTime;
    /**
     * 测试数组最大的尺寸
     */
    private int maxSize;

    /**
     * 数组中数离自己排完序后的最大的位置
     */
    private Integer k;

    /**
     * 是否全为正数
     */
    private boolean positive = false;


    /**
     * @param testTime 测试几次
     * @param maxSize  测试数组最大的尺寸
     * @param positive 测试数据是否全为正数
     */
    public Comparator(int testTime, int maxSize, boolean positive) {
        this.testTime = testTime;
        this.maxSize = maxSize;
        this.positive = positive;
    }

    public Comparator(int testTime, int maxSize) {
        this.testTime = testTime;
        this.maxSize = maxSize;
    }

    /**
     * @param testTime 测试几次
     * @param maxSize  测试数组最大的尺寸
     * @param k        必须保证数组中数离自己排完序后的最大的位置
     */
    public Comparator(int testTime, int maxSize, Integer k) {
        this.testTime = testTime;
        this.maxSize = maxSize;
        this.k = k;
    }

    public void start(Sortable sortable) {

        int maxValue = 100;
        boolean succeed = true;

        for (int i = 0; i < testTime; i++) {
            int[] arr1;
            int[] arr2;

            if (k == null) {
                arr1 = generateRandomArray(maxSize, maxValue, positive);
                arr2 = copyArray(arr1);
                sortable.sort(arr1);
            } else {
                // 需要生产的数组中数离自己排完序后的最大的位置 <= k
                arr1 = generateRandomArrayLessK(maxSize, k);
                arr2 = copyArray(arr1);
                sortable.sort(arr1, k);
            }

            comparator(arr2);

            if (!isEqual(arr1, arr2)) {
                succeed = false;
                break;
            }

            System.out.println(succeed ? "Nice!" : "Fucking fucked!");
        }

        System.out.println(succeed ? "All Nice!" : "Fucking fucked!");

        if (!succeed) {
            int[] arr;
            if (k != null) {
                arr = generateRandomArrayLessK(maxSize, k);
                printArray(arr);
                sortable.sort(arr, k);
            } else {
                arr = generateRandomArray(maxSize, maxValue, positive);
                printArray(arr);
                sortable.sort(arr);
            }
            printArray(arr);
        }
    }


    public static int[] generateRandomArrayLessK(int maxSize, int k) {
        // Math.random() -> [0,1) 所有的小数，等概率返回一个
        // Math.random() * N -> [0,N) 所有的小数，等概率返回一个
        // (int) Math.random() * N -> [0,N - 1] 所有的整数，等概率返回一个
        // 数组的长度随机
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];

        // 随机生成一个3位数
        int shift = new Random().nextInt() % 1000;

        for (int i = 0; i < arr.length; i++) {
            // 为什么要相减 shift？ 答： 因为不相减就不可能产生负数的测试数据
            arr[i] = i - shift;
        }

        // 只生成了一种数组
        if (arr.length >= k) {
            QuickSort.swap(arr, 0, k - 1);
        }

        return arr;
    }

    /**
     * @param maxSize  数组的最大长度
     * @param maxValue 数组中的最大值
     * @param positive 是否所有值为正数
     * @return
     */
    public static int[] generateRandomArray(int maxSize, int maxValue, boolean positive) {
        // Math.random() -> [0,1) 所有的小数，等概率返回一个
        // Math.random() * N -> [0,N) 所有的小数，等概率返回一个
        // (int) Math.random() * N -> [0,N - 1] 所有的整数，等概率返回一个
        // 数组的长度随机
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            // 为什么要相减？ 答： 因为不相减就不可能产生负数的测试数据
            if (positive) {
                arr[i] = (int) ((maxValue + 1) * Math.random());
            } else {
                arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
            }
        }

        return arr;
    }


    public static void printArray(int[] arr) {
        for (int i : arr) {
            System.out.print(i + ",");
        }
        System.out.println();
    }

    private static int[] copyArray(int[] arr1) {
        int[] copy = new int[arr1.length];
        System.arraycopy(arr1, 0, copy, 0, arr1.length);
        return copy;
    }

    /**
     * 使用系统的算法来对比检测自己的算法
     *
     * @param arr 需要排序的算法
     */
    public void comparator(int[] arr) {
        Arrays.sort(arr);
    }

    /**
     * 判断自己的算法排序的结果和系统的是否一致
     *
     * @param arr1 自己的算法排序的结果
     * @param arr2 系统算法排序的结果
     * @return 一致 true, 不一致 false
     */
    private boolean isEqual(int[] arr1, int[] arr2) {
        if (arr1.length != arr2.length) {
            return false;
        }

        for (int i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]) {
                return false;
            }
        }

        return true;
    }

}
